package com.xiaoma.factorybean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * https://juejin.cn/post/6844904099662544903
 * @author maj
 * @ClassName MyFactoryBean
 * @Description
 * @date 2020-11-30 21:32
 *
 * 一些复杂的bean，可以通过factorybean来产生，getObject返回的就是对应的bean
 */

public class MyFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean {

  private static final Logger logger = LoggerFactory.getLogger(MyFactoryBean.class);
  private String interfaceName;
  private Object target;
  private Object proxyObj;

  @Override
  public void destroy() throws Exception {

  }

  @Override
  public Object getObject()  {
    logger.info("getObject......");
    System.out.println("getObject......");
    return proxyObj;
  }

  @Override
  public Class<?> getObjectType() {
    return proxyObj == null ? Object.class : proxyObj.getClass();
  }

  @Override
  public boolean isSingleton() {
    return true;
  }

  @Override
  public void afterPropertiesSet() throws Exception {

    proxyObj = Proxy.newProxyInstance(
        this.getClass().getClassLoader(),
        new Class[] { Class.forName(interfaceName) },
        new InvocationHandler() {
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            logger.info("invoke method......" + method.getName());
            logger.info("invoke method before......" + System.currentTimeMillis());
            Object result = method.invoke(target, args);
            logger.info("invoke method after......" + System.currentTimeMillis());
            return result;            }
        });
    logger.info("afterPropertiesSet......");
  }

  public String getInterfaceName() {
    return interfaceName;
  }

  public void setInterfaceName(String interfaceName) {
    this.interfaceName = interfaceName;
  }

  public Object getTarget() {
    return target;
  }

  public void setTarget(Object target) {
    this.target = target;
  }

  public Object getProxyObj() {
    return proxyObj;
  }

  public void setProxyObj(Object proxyObj) {
    this.proxyObj = proxyObj;
  }

}
